package com.icexxx.lathe;

import javax.servlet.http.HttpServletRequest;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class DefaultRepeatInterceptor extends AbstractRepeatInterceptor {
    public static final String SEPARATOR = "_z_";
    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    @Autowired(required = false)
    private RedisTemplate<String, String> redisTemplate;

    private long timeout = 6000;

    private String code = "code";

    private String msg = "message";

    private String message = "请勿重复提交,请稍后再试!";

    private int codeValue = 776;

    public void init(LatheProperties latheProperties) {
        if (latheProperties != null) {
            String timeoutValue = latheProperties.getTimeout();
            String codeValue = latheProperties.getCode();
            String msgValue = latheProperties.getMsg();
            String messageValue = latheProperties.getMessage();
            String codeNumValue = latheProperties.getCodeValue();
            if (StringUtils.hasText(timeoutValue)) {
                try {
                    timeout = Long.parseLong(timeoutValue);
                } catch (NumberFormatException e) {
                    // NOP
                }
            }
            if (StringUtils.hasText(codeValue)) {
                code = codeValue;
            }
            if (StringUtils.hasText(msgValue)) {
                msg = msgValue;
            }
            if (StringUtils.hasText(messageValue)) {
                message = messageValue;
            }
            if (StringUtils.hasText(codeNumValue)) {
                try {
                    this.codeValue = Integer.parseInt(codeNumValue);
                } catch (NumberFormatException e) {
                    // NOP
                }
            }

        }
    }

    @Override
    public boolean handle(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        String key = requestURI.replace("/", SEPARATOR);
        String sessionId = sessionIdInfo();
        key = key + SEPARATOR + sessionId;
        Map<String, String[]> parameterMap = request.getParameterMap();
        String md5 = md5(parameterMap);
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String md5Redis = null;
        md5Redis = opsForValue.get(key);
        if (md5Redis == null) {
            opsForValue.set(key, md5, timeout, TimeUnit.MILLISECONDS);
            return true;
        }
        if (md5Redis.equals(md5)) {
            return false;
        }
        opsForValue.set(key, md5, timeout, TimeUnit.MILLISECONDS);
        return true;
    }

    private String md5(Map<String, String[]> parameterMap) {
        byte[] writeValueAsBytes = new byte[] {};
        try {
            writeValueAsBytes = OBJECT_MAPPER.writeValueAsBytes(parameterMap);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        String mapStr = null;
        try {
            mapStr = new String(writeValueAsBytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return md5(mapStr);
    }

    private String md5(String mapStr) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(mapStr.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        byte[] digest = messageDigest.digest();
        BigInteger bigInteger = new BigInteger(1, digest);
        return bigInteger.toString(16);
    }

    @Override
    protected String sessionIdInfo() {
        return IceSessionUtil.sessionId();
    }

    @Override
    public String messageInfo() {
        return message;
    }

    @Override
    protected String codeInfo() {
        return code;
    }

    @Override
    protected String msgInfo() {
        return msg;
    }

    @Override
    protected String concatMessage(String message, String code, String msg, int codeValue) {
        StringBuilder sb = new StringBuilder();
        sb.append("{ \"");
        sb.append(code);
        sb.append("\": ");
        sb.append(codeValue);
        sb.append(", \"");
        sb.append(msg);
        sb.append("\": \"");
        sb.append(message);
        sb.append("\" }");
        return sb.toString();
    }

    @Override
    protected int codeValueInfo() {
        return codeValue;
    }

}
